import { useEffect, useRef, useState } from "react";
import { MusicStateType } from "../../views/Music/Music";
import { useAppDispatch, useAppSelector } from "../../utils/store/hooks";
import { songApi, songListApi } from "../../utils/backend/server";
import { Song } from "../../utils/domain/Song";
import {
  goBack,
  setCurrentSongInfo,
  updateAllSongList,
  updatePlayHistory,
  updatePlayMode,
} from "../../utils/store/songSlice";
import {
  DeleteOutlined,
  PauseCircleOutlined,
  PlayCircleOutlined,
  StepBackwardOutlined,
  StepForwardOutlined,
} from "@ant-design/icons";
import styles from "./Music.module.css";

import React from "react";
import {
  calRest,
  HOUR_MILLS,
  MIN_MILLS,
  SEC_MILLS,
} from "../../views/Functions/children/Timer/Timer";
import { useNavigate } from "react-router-dom";
import {
  Button,
  Input,
  message,
  Modal,
  Popconfirm,
  Space,
  Table,
  TableProps,
} from "antd";
import { SongList, SongListVo } from "../../utils/domain/SongList";

let timer: null | NodeJS.Timeout = null;
let time = 0;

const timerConverter = (time: number) => {
  const hour = calRest(time * 1000, HOUR_MILLS);
  const min = calRest(hour.rest, MIN_MILLS);
  const sec = calRest(min.rest, SEC_MILLS);
  return time > HOUR_MILLS
    ? `${hour.val}:${min.val}:${sec.val}`
    : `${min.val < 10 ? 0 : ""}${min.val}:${sec.val < 10 ? 0 : ""}${sec.val}`;
};

const Controller = (props: {
  musicState: MusicStateType;
  play: () => void;
  pause: () => void;
  prev: () => void;
  next: () => void;
}) => {
  return (
    <div className={styles.controller}>
      <StepBackwardOutlined
        // onClick={props.backward}
        onClick={props.prev}
        className={styles.backward}
      />
      <div className={styles.play}>
        {/* onClick={props.play} */}
        {props.musicState === "paused" ? (
          <PlayCircleOutlined
            onClick={() => {
              props.play();
            }}
          />
        ) : (
          <PauseCircleOutlined
            onClick={() => {
              props.pause();
            }}
          />
        )}
      </div>
      {/* onClick={props.forward} */}
      <StepForwardOutlined onClick={props.next} className={styles.forward} />
    </div>
  );
};

const Timeline = (props: {
  musicState: MusicStateType;
  elapsedTime: number;
  updateElapsedTime: (time: number) => void;
}) => {
  const currentSong = useAppSelector((state) => state.song).currentSongInfo;

  useEffect(() => {
    return () => {
      props.updateElapsedTime(0);
    };
  }, []);
  return (
    <div className={styles.timeline}>
      <img
        src={currentSong.thumbnail || "lp.webp"}
        alt=""
        className={styles.thumbnail}
      />

      <div className={styles.right}>
        <div className={styles.top}>
          <span>{currentSong.title}</span>
          <p>
            <span>{timerConverter(props.elapsedTime || 0)}</span>
            <span className={styles.slash}>/</span>
            <span>{timerConverter(currentSong.duration)}</span>
          </p>
        </div>
        <div
          className={styles.bot}
          onClick={(e) => {
            if (props.musicState === "paused") return;
            props.updateElapsedTime(
              (e.nativeEvent.offsetX / 370) * currentSong.duration
            );
          }}
        >
          <div className={styles.line}></div>
          <div
            className={styles.dot}
            style={{
              left: (props.elapsedTime / currentSong.duration) * 360 + "px",
            }}
          ></div>
        </div>
      </div>
    </div>
  );
};

const ChangeListName = (props: { record: SongList; refresh: () => void }) => {
  const [val, setVal] = useState<string>(props.record.listName);

  const changeListName = (id: number, listName: string) => {
    songListApi.changeListName(id, listName).then(() => {
      props.refresh();
    });
  };

  return (
    <>
      <input
        value={val}
        onChange={(e) => setVal(e.target.value)}
        className={styles.changeListName}
      />
      {props.record.listName === val ? (
        ""
      ) : (
        <Button
          type="link"
          onClick={() => changeListName(props.record.id, val)}
        >
          rename
        </Button>
      )}
      {/* <Input value={val} onChange={(e) => setVal(e.target.value)} />{" "} */}
    </>
  );
};

const CreateList = (props: {
  showModal: boolean;
  hideModal: () => void;
  refresh: (cb: (data: SongListVo[]) => void) => void;
}) => {
  const [val, setVal] = useState<string>("");
  const [list, setList] = useState<SongListVo[]>([]);
  // const dispatch = useAppDispatch();
  const refresh = () => {
    props.refresh((data) => setList(data));
  };

  const createNewList = () => {
    songListApi.createSongList(val).then(() => {
      refresh();
      message.success("create new song list success!");
    });
  };

  useEffect(() => {
    if (props.showModal) refresh();
  }, [props.showModal]);

  const switchCurrentList = (value: string) => {
    const cur = list.find((val) => val.listName === value);
    if (cur === undefined) {
      message.error("unknown error: cannot find selected list!");
      return;
    }
    songListApi.switchCurrentList(value).then(() => {
      message.success("change current list success!");
      refresh();
    });
  };

  const deleteCurrentList = (id: number) => {
    songListApi.removeList(id).then((res) => {
      if (!res.success) {
        message.error(res.msg);
        return;
      }
      refresh();
    });
  };
  const columns: TableProps<SongListVo>["columns"] = [
    {
      title: "Name",
      dataIndex: "listName",
      key: "listName",
      render: (_, record) => {
        return <ChangeListName record={record} refresh={refresh} />;
      },
    },
    {
      title: "Operation",
      dataIndex: "operation",
      key: "operation",
      render: (_, record) => {
        return (
          <div key={record.id + "ope"}>
            <Space>
              <Button
                type="primary"
                onClick={() => {
                  switchCurrentList(record.listName);
                }}
              >
                use
              </Button>
              <Button
                type="primary"
                danger
                onClick={() => {
                  deleteCurrentList(record.id);
                }}
              >
                delete
              </Button>
            </Space>
          </div>
        );
      },
    },
  ];

  return (
    <>
      <Modal
        title="Lists:"
        open={props.showModal}
        onOk={props.hideModal}
        onCancel={props.hideModal}
      >
        <p className={styles.addListBox}>
          <Input
            value={val}
            placeholder="list name"
            style={{ width: 300, marginRight: 50 }}
            onChange={(e) => setVal(e.target.value)}
          />
          <Button type="primary" onClick={createNewList}>
            add
          </Button>
        </p>
        <h2 className={styles.switchList}>manage list:</h2>
        <Table dataSource={list} columns={columns} rowKey={"id"} />
      </Modal>
    </>
  );
};

const PlayList = (props: { showList: boolean; hideList: () => void }) => {
  const [isModalOpen, setIsModalOpen] = useState(false);
  const songStore = useAppSelector((state) => state.song);
  const currentList = songStore.allSongList.find((val) => val.currentList);
  const dispatch = useAppDispatch();

  const refresh = (setList: (data: SongListVo[]) => void) => {
    songListApi.getAllListData().then((data) => {
      dispatch(updateAllSongList(data));
      setList(data);
    });
  };
  // useEffect(() => {
  //   const unsubscribe = store.subscribe(() => {
  //   });

  //   return () => {
  //     unsubscribe();
  //   };
  // }, []);

  return (
    <div
      className={styles.playList}
      style={{ display: props.showList ? "block" : "none" }}
    >
      <h2>
        <div className={styles.createList} onClick={() => setIsModalOpen(true)}>
          <img src="/create.png" alt="add play list" />
          <Space>
            <span>Play List: </span>
            <span>
              {songStore.allSongList.find((val) => val.currentList === "1")
                ?.listName || ""}
            </span>
          </Space>
        </div>
        <img src="/close.png" alt="close" onClick={props.hideList} />
      </h2>
      {currentList?.songs
        .filter((val) => val)
        .map((val, seq) => {
          return (
            <p className={styles.line} key={val.id + seq}>
              <span className={styles.seq}>{seq + 1}</span>
              <span className={styles.name}>{val.title}</span>
              <span className={styles.author}>{val.author}</span>
              <span className={styles.duration}>
                {timerConverter(val.duration)}
              </span>
              <span className={styles.del}>
                <Popconfirm
                  title="Delete the song?"
                  description="Are you sure to delete all the songs?"
                  onConfirm={() => {
                    songListApi
                      .removeSongsFromList(currentList.id, [val.id])
                      .then((data) => {
                        message[data.success ? "success" : "error"](data.msg);
                        refresh(() => {});
                      });
                  }}
                >
                  <DeleteOutlined />
                </Popconfirm>
              </span>
            </p>
          );
        })}

      <CreateList
        showModal={isModalOpen}
        hideModal={() => {
          setIsModalOpen(false);
        }}
        refresh={refresh}
      />
    </div>
  );
};

const Mode = () => {
  const [show, setShow] = useState<boolean>(false);
  const to = useNavigate();
  const dispatch = useAppDispatch();
  const songStore = useAppSelector((state) => state.song);

  useEffect(() => {
    message.success(songStore.playMode + " mode");
  }, [songStore.playMode]);

  return (
    <>
      <PlayList showList={show} hideList={() => setShow(false)} />
      <div className={styles.mode}>
        <img
          src="/loop.png"
          alt="mode"
          className={styles.modeBut}
          onClick={() => {
            dispatch(updatePlayMode(null));
          }}
        />

        {/* <div className={styles.listWrp}> */}
        <img
          src="/list.png"
          alt="list"
          className={styles.modeBut}
          onClick={() => setShow((val) => !val)}
        />
        {/* </div> */}

        <img
          src="/song.png"
          alt="song png"
          className={styles.modeBut}
          onClick={() => {
            to("/songManagement");
          }}
        />
      </div>
    </>
  );
};

export const PlayBar = () => {
  const [elapsedTime, setElapsedTime] = useState<number>(0);
  const au = useRef<null | HTMLAudioElement>(null);
  const [musicState, setMusicState] = useState<MusicStateType>("paused");
  const store = useAppSelector((state) => state.song);
  const dispatch = useAppDispatch();

  useEffect(() => {
    if (!au.current || !store.currentSongInfo.mp3) return;
    au.current.src = songApi.song() + store.currentSongInfo.mp3;
    dispatch(updatePlayHistory(store.currentSongInfo));
  }, [store.currentSongInfo]);

  useEffect(() => {
    if (musicState === "paused") {
      setElapsedTime(time);
      timer && clearInterval(timer);
    } else {
      // time = 0;
      timer = setInterval(() => {
        time++;
        // props.updateElapsedTime(time);
        setElapsedTime(time);
      }, 1000);
    }

    return () => {
      timer && clearInterval(timer);
    };
  }, [musicState]);

  const playNext = (s: null | Song, updateHistory: boolean = true) => {
    const toNext = (m: Song) => {
      if (au.current) au.current.src = songApi.song() + m.mp3;
      dispatch(updatePlayHistory(m));
      dispatch(setCurrentSongInfo(m));
      // dispatch(updatePlayHistory(m))
    };

    if (s) {
      toNext(s);
    } else {
      // const newList = store.allSongList.find(val=>val.currentList === '1')
      const list = store.allSongList.find(
        (val) => val.currentList === "1"
      )?.songs;
      if (!list) return;
      const last = list.findIndex((val) => val.id === store.currentSongInfo.id);
      switch (store.playMode) {
        case "iterate":
          toNext(list[(last + 1) % list.length]);
          break;
        case "loop":
          toNext(store.currentSongInfo);
          break;
        case "shuffle":
          toNext(list[new Date().valueOf() % list.length]);
          break;
      }
    }

    setTimeout(() => {
      au.current && au.current.play();
      setMusicState("playing");
    }, 1000);
  };

  const ended = () => {
    setMusicState("paused");
    time = 0;
  };

  return (
    <div className={styles.playBar}>
      {/* backward={() => {}} forward={() => {}} play={() => {}}  */}
      <Controller
        musicState={musicState}
        play={() => {
          setMusicState("playing");
          au.current && au.current.play();
        }}
        pause={() => {
          au.current && au.current.pause();
          setMusicState("paused");
        }}
        prev={() => {
          ended();
          // console.log(store.history);
          const currentList = store.allSongList.find(
            (val) => val.currentList === "1"
          )?.songs;

          const cur =
            store.playHistory[
              store.playHistory.length - 2 < 0
                ? 0
                : store.playHistory.length - 2
            ];
          if (!currentList) return;
          const next = currentList.find((val) => val.id === cur);
          next && playNext(next, false);
          dispatch(goBack(null));
        }}
        next={() => {
          // dispatch(updatePlayHistory(store.currentSongInfo))
          ended();
          playNext(null);
        }}
      />
      <Timeline
        musicState={musicState}
        elapsedTime={elapsedTime}
        updateElapsedTime={(newPos) => {
          time = newPos;
          au.current && (au.current.currentTime = newPos);
          setElapsedTime(newPos);
        }}
      />
      <Mode />
      <audio
        ref={au}
        onEnded={() => {
          ended();
          playNext(null);
        }}
      ></audio>
    </div>
  );
};
